import itertools
import copy
from framework.common import util
from framework.core.crawler_result import Result


class Task(object):
    def __init__(self):
        self.url = None  # required
        self.metadata = dict()  # metadata.tt & metadata.batchId are required
        self.parser = None  # required
        self.desc = None
        self.tags = dict()
        self.parent_result = None

    @classmethod
    def from_json(cls, data):
        if data is None:
            return None
        else:
            obj = cls()
            obj.url = data.get("url")
            obj.metadata = data.get("metadata")
            obj.parser = data.get("parser")
            obj.desc = data.get("desc")
            obj.tags = data.get("tags")
            obj.parent_result = Result.from_json(data.get("parent_result"))
            return obj

    def __repr__(self):
        return "url:%s, metadata:%s, parser:%s, desc:%s, tag:%s" % (self.url, self.metadata, self.parser, self.desc, self.tags)

    @staticmethod
    def _do_cleaning(task):
        task.url = task.url.replace("\"", "").replace("\'", "").replace("\\", "")
        return task

    @classmethod
    def create_tasks(cls, obj, parser, parent_result=None, metadata=dict(), tags=dict()):
        """
        :param obj: [<url>, {metadata}, desc, {tags}]
        :param parser: name of parser
        :param parent_result:
        :param metadata: {"tt": "CoreProductsBestSellers", "td": "init", "tp": "first_page"}
        :param tags:
        :return:
        """
        results = list()
        if obj is None or obj == "":
            return results
        if isinstance(obj, list):  # JimmyMo 如果obj是一个list，则metadata和tags是从obj中获取
            for item in obj:
                if isinstance(item, tuple) or isinstance(item, list):
                    t = cls()
                    t.url = util.fstring(item[0])
                    if metadata:  # 有override metadata
                        t.metadata = {**t.metadata, **metadata}  # merge two dicts
                    else:  # 使用obj中自带的metadata
                        t.metadata = {**t.metadata, **item[1]} if len(item) > 1 else dict()  # merge two dicts
                    t.desc = item[2] if len(item) > 2 else None
                    if tags:  # 有override tags
                        t.tags = {**t.tags, **tags}
                    else:  # 使用obj中自带的tags
                        t.tags = {**t.tags, **item[3]} if item[3] and len(item) > 3 else dict()  # merge two dicts
                    t.parser = parser
                    t.parent_result = parent_result
                elif isinstance(item, str):
                    t = cls()
                    t.url = util.fstring(item)
                    t.parser = parser
                    t.parent_result = parent_result
                    t.metadata = {**t.metadata, **metadata}
                    t.tags = {**t.tags, **tags}
                else:
                    raise ValueError("only support URL(string) or List<String> or Tuple<String>...")
                results.append(t)
        elif isinstance(obj, str):
            t = cls()
            t.url = obj
            t.parser = parser
            t.parent_result = parent_result
            t.metadata = {**t.metadata, **metadata}
            t.tags = {**t.tags, **tags}
            results.append(t)
        else:
            raise ValueError("only support Task or List<Task>...")

        results = list(map(lambda item: Task._do_cleaning(item), results))
        return results

    def copy_tags(self, tags=None):
        if tags is None:
            tags = dict()
        return {**copy.deepcopy(self.tags), **tags}

    def copy_metadata(self, items=None):
        if items is None:
            items = dict()
        return {**copy.deepcopy(self.metadata), **items}

    def put_tag(self, key, value):
        self.tags[key] = value

    def get_tag(self, key):
        if key in self.tags:
            return self.tags[key]
        else:
            return None